package cn.wh.db.router.config;

import cn.wh.db.router.DBRoutingConfig;
import cn.wh.db.router.DBRoutingJoinPoint;
import cn.wh.db.router.dynamic.DynamicDataSource;
import cn.wh.db.router.enums.RoutingConstans;
import cn.wh.db.router.strategy.DBRoutingContext;
import cn.wh.db.router.strategy.IDBRoutingStrategy;
import cn.wh.db.router.strategy.impl.DefaultDBRouterStrategy;
import cn.wh.db.router.util.PropertyUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.support.TransactionTemplate;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author wh
 * @Description 数据源 配置解析
 * @Date 2023/3/28 12:17
 * @Version 1.0
 **/
public class DataSourceAutoConfig implements EnvironmentAware {

    /**
     * 数据源配置组
     */
    private Map<String, Map<String, Object>> dataSourceMap = new HashMap<>();

    /**
     * 默认数据源配置
     */
    private Map<String, Object> defaultDataSourceConfig;


    /**
     * 分库数量
     */
    private Integer dbCount;


    /**
     * 分表数量
     */
    private Integer tbCount;


    /**
     * 路由字段
     */
    private String routingKey;


    /**
     * 路由策略
     *
     * @return
     */
    private String routingStrategy;


    @ConditionalOnMissingBean
    @Bean
    public DBRoutingJoinPoint dbRoutingJoinPoint(DBRoutingConfig dbRoutingConfig) {
        return new DBRoutingJoinPoint(dbRoutingConfig);
    }


    /**
     * 数据源注入 dataSource
     *
     * @return
     */
    @Bean
    public DataSource dataSource() {
        // 创建数据源
        Map<Object, Object> targetDataSources = new HashMap<>();
        for (String dbInfo : dataSourceMap.keySet()) {
            Map<String, Object> objMap = dataSourceMap.get(dbInfo);
            targetDataSources.put(dbInfo, new DriverManagerDataSource(objMap.get("url").toString(), objMap.get("username").toString(), objMap.get("password").toString()));
        }

        // 设置数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(new DriverManagerDataSource(defaultDataSourceConfig.get("url").toString(), defaultDataSourceConfig.get("username").toString(), defaultDataSourceConfig.get("password").toString()));
        return dynamicDataSource;
    }


    @Bean
    public IDBRoutingStrategy defaultDBRouterStrategy(DBRoutingConfig dbRoutingConfig) {
        IDBRoutingStrategy defaultDBRouterStrategy = new DefaultDBRouterStrategy(dbRoutingConfig);
        DBRoutingContext.addDBRoutingStrategy(dbRoutingConfig.getRoutingKey(), defaultDBRouterStrategy);
        return defaultDBRouterStrategy;
    }


    /**
     * 路由属性配置注入
     *
     * @return
     */

    @Bean
    public DBRoutingConfig dbRoutingConfig() {
        return new DBRoutingConfig(dbCount, tbCount, routingKey, routingStrategy);
    }


    /**
     * 编程式事物解决 事物数据源事物问题
     *
     * @param dataSource
     * @return
     */
    @Bean
    public TransactionTemplate transactionTemplate(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);

        TransactionTemplate transactionTemplate = new TransactionTemplate();
        transactionTemplate.setTransactionManager(dataSourceTransactionManager);
        transactionTemplate.setPropagationBehaviorName("PROPAGATION_REQUIRED");
        return transactionTemplate;
    }


    @Override
    public void setEnvironment(Environment environment) {
        dbCount = Integer.valueOf(environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.DBCOUNT));
        tbCount = Integer.valueOf(environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.TBCOUNT));
        routingKey = environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.ROUTING_KEY);
        routingStrategy = environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.ROUTING_STRATEGY);
        // 分库分表数据源
        String dataSources = environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.LIST);
        assert dataSources != null;
        for (String dbInfo : dataSources.split(",")) {
            Map<String, Object> dataSourceProps = PropertyUtil.handle(environment, RoutingConstans.PREFIX + dbInfo, Map.class);
            dataSourceMap.put(dbInfo, dataSourceProps);
        }
        // 默认数据源
        String defaultData = environment.getProperty(RoutingConstans.PREFIX + RoutingConstans.DEFAULT);
        defaultDataSourceConfig = PropertyUtil.handle(environment, RoutingConstans.PREFIX + defaultData, Map.class);
    }
}
